﻿using Microsoft.Extensions.Hosting;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Channels;
using System.Threading.Tasks;

namespace RabiitMq.Server
{
    public class TwoRabbitMqHostServer : IHostedService
    {
        public IConnection _Connection { get; set; }
        public TwoRabbitMqHostServer(IConnection connection)
        {
            _Connection = connection;
        }

        public async Task StartAsync(CancellationToken cancellationToken)
        {

            #region  Fanout 广播交换机
            {
                //Channel.basicAck(用于肯定确认)
                //RabbitMQ 已知道该消息并且成功的处理消息，可以将其丢弃了
                //Channel.basicNack(用于否定确认)
                //Channel.basicReject(用于否定确认)
                //与 Channel.basicNack 相比少一个参数，不处理该消息，直接拒绝，可以将其丢弃了

                //IConnectionFactory factory = new ConnectionFactory//创建连接工厂对象
                //{
                //    HostName = "172.208.24.243",//IP地址
                //    VirtualHost = "/",
                //    Port = 5672,//端口号
                //    UserName = "admin",//用户账号
                //    Password = "123456"//用户密码
                //};
                ////2. 建立连接
                //IConnection con = factory.CreateConnection();//创建连接对象



                ////3. 创建信道
                //IModel channel = _Connection.CreateModel();//创建连接会话对象

                //channel.ExchangeDeclare(exchange: "amq.fanout", type: ExchangeType.Fanout, durable: true);
                //////声明一个队列
                ////channel.QueueDeclare(
                ////  queue: "hello.one",//消息队列名称

                ////  durable: true,//是否持久化,true持久化,队列会保存磁盘,服务器重启时可以保证不丢失相关信息。
                ////  exclusive: false,//是否排他,true排他的,如果一个队列声明为排他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除.
                ////  autoDelete: false,//是否自动删除。true是自动删除。自动删除的前提是：致少有一个消费者连接到这个队列，之后所有与这个队列连接的消费者都断开时,才会自动删除.
                ////  arguments: null //设置队列的一些其它参数
                ////   );

                //var queueName = channel.QueueDeclare().QueueName;
                //channel.QueueBind(queue: queueName,
                //      exchange: "amq.fanout",
                //      routingKey: "");
                ////Qos 防止多个消费者，能力不一致，导致系统信息堆积，每一次一个消费者只成功消费一个
                //channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);
                ////5. 构造消费者实例
                //var consumer = new EventingBasicConsumer(channel);

                //consumer.Received += (model, ea) =>
                //{
                //    byte[] body = ea.Body.ToArray();
                //    var message = Encoding.UTF8.GetString(body);
                //    Console.WriteLine($" [x] {message}");
                //    channel.BasicAck(ea.DeliveryTag, multiple: true); //消息确认
                //};
                //channel.BasicConsume(queue: queueName,
                //                     autoAck: false,
                //                     consumer: consumer);
            }
            #endregion

            #region direct 直连交换机
            {
                ////3. 创建信道
                //IModel channel = _Connection.CreateModel();//创建连接会话对象

                //channel.ExchangeDeclare(exchange: "one.Direct", type: ExchangeType.Direct, durable: true);
                //////声明一个队列
                ////channel.QueueDeclare(
                ////  queue: "hello.one",//消息队列名称

                ////  durable: true,//是否持久化,true持久化,队列会保存磁盘,服务器重启时可以保证不丢失相关信息。
                ////  exclusive: false,//是否排他,true排他的,如果一个队列声明为排他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除.
                ////  autoDelete: false,//是否自动删除。true是自动删除。自动删除的前提是：致少有一个消费者连接到这个队列，之后所有与这个队列连接的消费者都断开时,才会自动删除.
                ////  arguments: null //设置队列的一些其它参数
                ////   );

                //var queueName = channel.QueueDeclare().QueueName;
                //channel.QueueBind(queue: queueName,
                //      exchange: "one.Direct",
                //      routingKey: "two");
                ////Qos 防止多个消费者，能力不一致，导致系统信息堆积，每一次一个消费者只成功消费一个
                //channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);
                ////5. 构造消费者实例
                //var consumer = new EventingBasicConsumer(channel);

                //consumer.Received += (model, ea) =>
                //{
                //    byte[] body = ea.Body.ToArray();
                //    var message = Encoding.UTF8.GetString(body);
                //    Console.WriteLine($" [x] {message}");
                //    channel.BasicAck(ea.DeliveryTag, multiple: true); //消息确认
                //};
                //channel.BasicConsume(queue: queueName,
                //                     autoAck: false,
                //                     consumer: consumer);
            }
            #endregion

            #region Topic 主题交换机
            {
                ////3. 创建信道
                //IModel channel = _Connection.CreateModel();//创建连接会话对象

                //channel.ExchangeDeclare(exchange: "one.Topic", type: ExchangeType.Topic, durable: true);
                //////声明一个队列
                ////channel.QueueDeclare(
                ////  queue: "hello.one",//消息队列名称

                ////  durable: true,//是否持久化,true持久化,队列会保存磁盘,服务器重启时可以保证不丢失相关信息。
                ////  exclusive: false,//是否排他,true排他的,如果一个队列声明为排他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除.
                ////  autoDelete: false,//是否自动删除。true是自动删除。自动删除的前提是：致少有一个消费者连接到这个队列，之后所有与这个队列连接的消费者都断开时,才会自动删除.
                ////  arguments: null //设置队列的一些其它参数
                ////   );

                //var queueName = channel.QueueDeclare().QueueName;
                //// * 只能匹配一级  #可以匹配多级    一级代码.后面只能跟一个单词 加点分割代表规范  # 可以匹配多个单词
                //channel.QueueBind(queue: queueName,
                //      exchange: "one.Topic",
                //      // * 只能匹配一级  #可以匹配多级    一级代码.后面只能跟一个单词 加点分割代表规范  # 可以匹配多个单词
                //      routingKey: "ems.#");
                ////Qos 防止多个消费者，能力不一致，导致系统信息堆积，每一次一个消费者只成功消费一个
                //channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);
                ////5. 构造消费者实例
                //var consumer = new EventingBasicConsumer(channel);

                //consumer.Received += (model, ea) =>
                //{
                //    byte[] body = ea.Body.ToArray();
                //    var message = Encoding.UTF8.GetString(body);
                //    Console.WriteLine($" [x] {message}");
                //    channel.BasicAck(ea.DeliveryTag, multiple: true); //消息确认
                //};
                //channel.BasicConsume(queue: queueName,
                //                     autoAck: false,
                //                     consumer: consumer);
            }
            #endregion

            #region herder 死信交换机
            {
                //IModel channe2 = _Connection.CreateModel();//创建连接会话对象
                //channe2.ExchangeDeclare(exchange: "sixin.hou", type: ExchangeType.Direct, true);
                //channe2.QueueDeclare(queue: "sixin.hou.quque.one",
                //durable: true,//是否持久化,true持久化,队列会保存磁盘,服务器重启时可以保证不丢失相关信息。
                //exclusive: false,//是否排他,true排他的,如果一个队列声明为排他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除.
                //autoDelete: false,//是否自动删除。true是自动删除。自动删除的前提是：致少有一个消费者连接到这个队列，之后所有与这个队列连接的消费者都断开时,才会自动删除.
                //arguments: null //设置队列的一些其它参数
                //);
                //channe2.QueueBind(queue: "sixin.hou.quque.one", exchange: "sixin.hou", routingKey: "sixin.hou.quque");

                ////Qos 防止多个消费者，能力不一致，导致系统信息堆积，每一次一个消费者只成功消费一个
                //channe2.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);
                ////5. 构造消费者实例
                //var consumer = new EventingBasicConsumer(channe2);

                //consumer.Received += (model, ea) =>
                //{
                //    byte[] body = ea.Body.ToArray();
                //    var message = Encoding.UTF8.GetString(body);
                //    Console.WriteLine($" [x] {message}");
                //    channe2.BasicAck(ea.DeliveryTag, multiple: true); //消息确认
                //};
                //channe2.BasicConsume(queue: "sixin.hou.quque.one",
                //                     autoAck: false,
                //                     consumer: consumer);
            }
            #endregion

            #region  插件 延迟消息功能的插件
            {
                //IModel channe2 = _Connection.CreateModel();//创建连接会话对象
                //channe2.ExchangeDeclare(exchange: "delay.direct", type: "x-delayed-message", durable: true, arguments: new Dictionary<string, object>
                //{
                //    { "x-delayed-type", "direct" }
                //});
                //channe2.QueueDeclare(queue: "delay.quequ",
                //         durable: true,
                //exclusive: false,
                //autoDelete: false,
                //arguments: null);

                //channe2.QueueBind(queue: "delay.quequ", exchange: "delay.direct", routingKey: "delay");
                ////Qos 防止多个消费者，能力不一致，导致系统信息堆积，每一次一个消费者只成功消费一个
                //channe2.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);
                ////5. 构造消费者实例
                //var consumer = new EventingBasicConsumer(channe2);

                //consumer.Received += (model, ea) =>
                //{
                //    byte[] body = ea.Body.ToArray();
                    
                //    var message = Encoding.UTF8.GetString(body);
                //    Console.WriteLine($" [x] {message}");
                //    //channe2.BasicAck(ea.DeliveryTag, multiple: true); //消息确认
                //};
                //channe2.BasicConsume(queue: "delay.quequ",
                //                     autoAck: false,
                //                     consumer: consumer);
            }
            #endregion

            #region  消息消费成功回调通知
            {
                //IModel channel = _Connection.CreateModel();//创建连接会话对象
                //channel.ConfirmSelect();//开启消息确认模式
                //                        //发布消息    
                //                        //exchange：交换机名称
                //                        //mandatory为true时，表示如果消息没有被正确路由，消息将退回消息的生产者 如果设置为false，那么broker端自动删除该消息。
                //                        //routingKey：路由键
                //                        //props：消息属性字段，比如消息头部信息等等
                //                        //body：消息主体部分
                //                        //channel.BasicReturn += (obj, eg) =>
                //                        //{

                ////};
                //channel.ExchangeDeclare(exchange: "CallBack.Direct",
                //                    type: ExchangeType.Direct,
                //                    durable: true //是否持久化,true持久化
                //                    );
                //channel.QueueDeclare(queue: "CallBack",
                //           durable: true,//是否持久化,true持久化,队列会保存磁盘,服务器重启时可以保证不丢失相关信息。
                //  exclusive: false,//是否排他,true排他的,如果一个队列声明为排他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除.
                //  autoDelete: false,//是否自动删除。true是自动删除。自动删除的前提是：致少有一个消费者连接到这个队列，之后所有与这个队列连接的消费者都断开时,才会自动删除.
                //  arguments: null //设置队列的一些其它参数
                //  );
                //channel.QueueBind(queue: "CallBack",
                // exchange: "CallBack.Direct",
                // routingKey: "CallBack");
                //var properties = channel.CreateBasicProperties();
                //properties.DeliveryMode = 2;//1非持久化、2是持久化  消息如队列持久化 控制单个消息持久化（个性化）

                ////Qos 防止多个消费者，能力不一致，导致系统信息堆积，每一次一个消费者只成功消费一个
                //channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);
                ////5. 构造消费者实例
                //var consumer = new EventingBasicConsumer(channel);

                //consumer.Received += (model, ea) =>
                //{
                //    byte[] body = ea.Body.ToArray();
                //    var message = Encoding.UTF8.GetString(body);
                //    Console.WriteLine(ea.BasicProperties.CorrelationId);
                //    Console.WriteLine($" [x] {message}");
                //    channel.BasicAck(ea.DeliveryTag, multiple: true); //消息确认

                //    //消息消费成功 开始回调通知
                //    channel.BasicPublish(
                //         exchange: "",
                //         routingKey: ea.BasicProperties.ReplyTo,
                //         mandatory: true,
                //         basicProperties: properties, //控制单个消息持久化（个性化）
                //         body: body);
                //};
                ////开始监听队列
                //channel.BasicConsume(queue: "CallBack",
                //                     autoAck: false,
                //                     consumer: consumer);
            }
            #endregion
        }

        public async Task StopAsync(CancellationToken cancellationToken)
        {
            Console.WriteLine("关闭项目");
        }
    }
}
